#!/bin/sh

set -e
set -u

echo "Install the Tor Browser"

# Import the TBB_INSTALL, TBB_PROFILE, TBB_EXT and
# TOR_LAUNCHER_INSTALL variables, which contains the paths we will
# split TBB's actual browser (binaries etc), user data and extension
# into. While this differs from how the TBB organizes the files, the
# end result will be the same, and it's practical since when creating
# a new browser profile we can simply copy the profile directory
# without duplicating all extensions.
. /usr/local/lib/tails-shell-library/tor-browser.sh

download_and_verify_files() {
    local base_url bundles destination apt_proxy
    base_url="${1}"
    bundles="${2}"
    destination="${3}"

    # Use the builder's caching APT proxy, if any
    apt_proxy="$(apt-config --format '%v' dump Acquire::http::Proxy)"
    if [ -n "${apt_proxy}" ]; then
        export HTTP_PROXY="${apt_proxy}"
        export http_proxy="${apt_proxy}"
        export HTTPS_PROXY="${apt_proxy}"
        export https_proxy="${apt_proxy}"
    fi

    echo "${bundles}" | while read expected_sha256 tarball; do
        (
            cd "${destination}"
            echo "Fetching ${base_url}/${tarball} ..."
            curl --remote-name "${base_url}/${tarball}"
        )
        actual_sha256="$(sha256sum "${destination}/${tarball}" | cut -d' ' -f1)"
        if [ "${actual_sha256}" != "${expected_sha256}" ]; then
            echo "SHA256 mismatch for ${tarball}" >&2
            exit 1
        fi
    done
}

install_tor_browser() {
    local bundle destination tmp prep torlauncher_xpi_path torlauncher_version
    bundle="${1}"
    destination="${2}"

    tmp="$(mktemp -d)"
    tar -xf "${bundle}" -C "${tmp}" tor-browser_en-US
    prep="${tmp}"/tor-browser_en-US/Browser

    # Enable our myspell/hunspell dictionaries. TBB only provides the
    # one for en-US, but Debian's seems more comprehensive, so we'll
    # only use Debian's dictionaries.
    rm -f "${prep}"/dictionaries/*
    for f in /usr/share/hunspell/*.aff /usr/share/hunspell/*.dic; do
        ln -s "${f}" "${prep}"/dictionaries/
    done

    # Let's use the libstdc++ that the Tor Browser is intended to be used with,
    # instead of the system one.
    cp "${prep}"/TorBrowser/Tor/libstdc++.so.6 "${prep}"

    # We don't need the Tor binary, the shared libraries Tor needs
    # (but Firefox doesn't) and documentation shipped in the TBB.
    rm -r "${prep}"/TorBrowser/Tor "${prep}"/TorBrowser/Docs

    # We don't want tor-launcher to be part of the regular browser
    # profile but we want to keep it as a standalone application
    # when Tails is started in "bridge mode".
    torlauncher_xpi_path="${prep}/TorBrowser/Data/Browser/profile.default/extensions/tor-launcher@torproject.org.xpi"
    7z x -o"${TOR_LAUNCHER_INSTALL}" "${torlauncher_xpi_path}"
    torlauncher_version="$(sed -n \
        's,^        <em:version>\([0-9\.]\+\)</em:version>,\1,p' \
        "${TOR_LAUNCHER_INSTALL}/install.rdf")"
    cat > "${TOR_LAUNCHER_INSTALL}/application.ini" << EOF
[App]
Vendor=TorProject
Name=TorLauncher
Version=${torlauncher_version}
BuildID=$(date +%Y%m%d)
ID=tor-launcher@torproject.org

[Gecko]
MinVersion=$(get_firefox_version "${prep}/application.ini")
MaxVersion=*.*.*

[Shell]
Icon=icon.png
EOF
    chmod -R a+rX "${TOR_LAUNCHER_INSTALL}"
    rm "${torlauncher_xpi_path}"

    # The Tor Browser will fail, complaining about an incomplete profile,
    # unless there's a readable TorBrowser/Data/Browser/Caches
    # in the directory where the firefox executable is located.
    mkdir -p "${prep}"/TorBrowser/Data/Browser/Caches

    mv "${prep}" "${destination}"

    rm -r "${tmp}"
}

install_langpacks_from_bundles() {
    local bundles_dir destination
    bundles_dir="${1}"
    destination="${2}"

    for tarball in "${bundles_dir}"/tor-browser-*.tar.xz; do
        locale="$(echo "${tarball}" | sed "s@^.*/tor-browser-.*_\(.*\)\.tar\.xz@\1@")"
        if [ "${locale}" = en-US ]; then
            continue
        fi
        xpi="tor-browser_${locale}/Browser/TorBrowser/Data/Browser/profile.default/extensions/langpack-${locale}@firefox.mozilla.org.xpi"
        (
            cd "${bundles_dir}"
            tar -xf "${tarball}" "${xpi}"
            mv "${xpi}" "${destination}"
        )
    done
}

get_firefox_version() {
    # The application.ini file
    local appini
    appini="${1}"
    sed -n 's/^Version=\(.*\)$/\1/p' "${appini}"
}

# Create and install a fake iceweasel package so we can install our
# desired Debian-packaged Iceweasel addons
install_fake_iceweasel_pkg() {
    local fake_version tmp
    fake_version="${1}"
    tmp="$(mktemp -d)"
    apt-get install --yes equivs
    cat > "${tmp}"/iceweasel.control << EOF
Section: web
Priority: optional
Homepage: https://tails.boum.org/
Standards-Version: 3.6.2

Package: iceweasel
Version: ${fake_version}
Maintainer: Tails developers <amnesia@boum.org>
Architecture: all
Description: (Fake) Iceweasel
 Make it possible to install Debian's Iceweasel addons without having to
 install a real Iceweasel.
EOF
    (
        cd "${tmp}"
        equivs-build "${tmp}"/iceweasel.control
        dpkg -i "${tmp}"/iceweasel_"${fake_version}"_all.deb
    )
    rm -R "${tmp}"
}

install_debian_extensions() {
    local destination
    destination="${1}"
    shift
    apt-get install --yes "${@}"
    ln -s /usr/share/xul-ext/adblock-plus/ \
          "${destination}"/'{d10d0bf8-f5b5-c8b4-a8b2-2b9879e08c5d}'
}

create_default_profile() {
    local tbb_profile extensions_dir destination
    tbb_profile="${1}"
    tbb_extensions_dir="${2}"
    destination="${3}"

    rsync -a --exclude bookmarks.html --exclude extensions \
          "${tbb_profile}"/ "${destination}"/

    # Remove TBB's default bridges
    sed -i '/extensions\.torlauncher\.default_bridge\./d' "${destination}"/preferences/extension-overrides.js

    mkdir -p "${destination}"/extensions
    for ext in "${tbb_extensions_dir}"/*; do
        ln -s "${ext}" "${destination}"/extensions/
    done
}

TBB_SHA256SUMS_FILE=/usr/share/tails/tbb-sha256sums.txt
TBB_TARBALLS="$(grep "\<tor-browser-linux32-.*\.tar.xz$" "${TBB_SHA256SUMS_FILE}")"

# We'll use the en-US bundle as our basis; only langpacks will be
# installed from the other bundles.
MAIN_TARBALL="$(echo "${TBB_TARBALLS}" | grep -o "tor-browser-linux32-.*_en-US.tar.xz")"
TBB_DIST_URL_FILE=/usr/share/tails/tbb-dist-url.txt
TBB_TARBALLS_BASE_URL="$(cat "${TBB_DIST_URL_FILE}")"

# The Debian Iceweasel extensions we want to install and make
# available in the Tor Browser.
DEBIAN_EXT_PKGS="xul-ext-adblock-plus"

TMP="$(mktemp -d)"
download_and_verify_files "${TBB_TARBALLS_BASE_URL}" "${TBB_TARBALLS}" "${TMP}"

install_tor_browser "${TMP}/${MAIN_TARBALL}" "${TBB_INSTALL}"

mkdir -p "${TBB_EXT}"
install_langpacks_from_bundles "${TMP}" "${TBB_EXT}"

rm -r "${TMP}"

# Let's put all the extensions from TBB in the global extensions
# directory...
mv "${TBB_INSTALL}"/TorBrowser/Data/Browser/profile.default/extensions/* "${TBB_EXT}"
rmdir "${TBB_INSTALL}"/TorBrowser/Data/Browser/profile.default/extensions

# ... and then install a few Iceweasel extension by using a fake
# Iceweasel equivs package to satisfy the dependencies.
FIREFOX_VERSION=$(get_firefox_version "${TBB_INSTALL}"/application.ini)
FAKE_ICEWEASEL_VERSION=${FIREFOX_VERSION}+fake1
install_fake_iceweasel_pkg "${FAKE_ICEWEASEL_VERSION}"
install_debian_extensions "${TBB_EXT}" ${DEBIAN_EXT_PKGS}

mkdir -p "${TBB_PROFILE}"
create_default_profile "${TBB_INSTALL}"/TorBrowser/Data/Browser/profile.default "${TBB_EXT}" "${TBB_PROFILE}"

# Create a copy of the Firefox binary, for use e.g. by Tor Launcher.
# It won't be subject to AppArmor confinement.
cp -a "${TBB_INSTALL}/firefox" "${TBB_INSTALL}/firefox-unconfined"

chown -R root:root "${TBB_INSTALL}" "${TBB_PROFILE}" "${TBB_EXT}"
chmod -R a+rX "${TBB_INSTALL}" "${TBB_PROFILE}" "${TBB_EXT}"

# Make the Tor Browser into the system's default web browser
update-alternatives --install /usr/bin/x-www-browser x-www-browser /usr/local/bin/tor-browser 99
update-alternatives --install /usr/bin/gnome-www-browser gnome-www-browser /usr/local/bin/tor-browser 99
sed -i 's/\<iceweasel\.desktop\>/tor-browser.desktop/' /etc/gnome/defaults.list
